From: tsteven4 Date: Tue, 8 Jan 2019 23:09:05 +0000 (-0700) Subject: refactor trackfilter. X-Git-Tag: archive/raspbian/1.10.0+ds-2+rpi1~1^2~12^2~8^2~45^2~1 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22Program/%22http:/www.example.com/cgi/%22https:/%22Program?a=commitdiff_plain;h=eb215a880182f6a984e9d323362f0cb13fae84c9;p=gpsbabel.git refactor trackfilter. use std::sort, stable_sort instead of qsort. use QList instead of malloc'd arrays. minimize the use of duplicated information (track_ct, track_pts, timeless_pts first_time, last_time), and maintain the remaining duplicated information (track_list, a possible sorted version of my_track_head). use auto some more. eliminate some redundant casting. eliminate atoi. --- diff --git a/trackfilter.cc b/trackfilter.cc index 3b11c9377..bc81790e7 100644 --- a/trackfilter.cc +++ b/trackfilter.cc @@ -36,18 +36,19 @@ #ifdef TRACKF_DBG #include #endif +#include // for QList<>::iterator, QList #include // for qint64, qPrintable #include // for QRegExp, QRegExp::WildcardUnix -#include // for QRegularExpression +#include // for QRegularExpression, QRegularExpression::CaseInsensitiveOption, QRegularExpression::PatternOptions #include // for QRegularExpressionMatch #include // for QString #include // for UTC, CaseInsensitive +#include // for sort, stable_sort #include // for assert +#include // for nan #include // for printf -#include // for abs, atoi, qsort +#include // for abs #include // for strlen, strchr, strcmp -#include // for tolower, isdigit -#include // for nan #include // for gmtime, strftime #if FILTERS_ENABLED || MINIMAL_FILTERS @@ -111,44 +112,14 @@ qint64 TrackFilter::trackfilter_parse_time_opt(const char* arg) return result; } -int TrackFilter::trackfilter_init_qsort_cb(const void* a, const void* b) +bool TrackFilter::trackfilter_init_sort_cb(const route_head* ha, const route_head* hb) { - const trkflt_t* ra = (const trkflt_t*) a; - const trkflt_t* rb = (const trkflt_t*) b; - const QDateTime dta = ra->first_time; - const QDateTime dtb = rb->first_time; - - if (dta > dtb) { - return 1; - } - if (dta == dtb) { - return 0; - } - return -1; + return trackfilter_get_first_time(ha) < trackfilter_get_first_time(hb); } -int TrackFilter::trackfilter_merge_qsort_cb(const void* a, const void* b) +bool TrackFilter::trackfilter_merge_sort_cb(const Waypoint* wa, const Waypoint* wb) { - const Waypoint* wa = *(Waypoint**)a; - const Waypoint* wb = *(Waypoint**)b; - const QDateTime dta = wa->GetCreationTime(); - const QDateTime dtb = wb->GetCreationTime(); - - if (dta > dtb) { - return 1; - } - if (dta == dtb) { - int seqno_a = gb_ptr2int(wa->extra_data); - int seqno_b = gb_ptr2int(wb->extra_data); - if (seqno_a > seqno_b) { - return 1; - } else if (seqno_a == seqno_b) { - return 0; - } else { - return -1; - } - } - return -1; + return wa->GetCreationTime() < wb->GetCreationTime(); } fix_type TrackFilter::trackfilter_parse_fix(int* nsats) @@ -180,6 +151,25 @@ fix_type TrackFilter::trackfilter_parse_fix(int* nsats) return fix_unknown; } +QDateTime TrackFilter::trackfilter_get_first_time(const route_head* track) +{ + if (QUEUE_EMPTY(&track->waypoint_list)) { + return QDateTime(); + } else { + return reinterpret_cast(QUEUE_FIRST(&track->waypoint_list))->GetCreationTime(); + } +} + +QDateTime TrackFilter::trackfilter_get_last_time(const route_head* track) +{ + if (QUEUE_EMPTY(&track->waypoint_list)) { + return QDateTime(); + } else { + return reinterpret_cast(QUEUE_LAST(&track->waypoint_list))->GetCreationTime(); + } +} + + void TrackFilter::trackfilter_fill_track_list_cb(const route_head* track) /* callback for track_disp_all */ { queue* elem, *tmp; @@ -201,30 +191,15 @@ void TrackFilter::trackfilter_fill_track_list_cb(const route_head* track) /* ca } } - track_list[track_ct].track = const_cast(track); - - int i = 0; Waypoint* prev = nullptr; QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { - track_pts++; - auto wpt = reinterpret_cast(elem); - if (!wpt->creation_time.isValid()) { - timeless_pts++; - } if (!(opt_merge && opt_discard) && need_time && (!wpt->creation_time.isValid())) { fatal(MYNAME "-init: Found track point at %f,%f without time!\n", wpt->latitude, wpt->longitude); } - i++; - if (i == 1) { - track_list[track_ct].first_time = wpt->GetCreationTime(); - } else if (i == track->rte_waypt_ct) { - track_list[track_ct].last_time = wpt->GetCreationTime(); - } - if (need_time && (prev != nullptr) && (prev->GetCreationTime() > wpt->GetCreationTime())) { if (opt_merge == nullptr) { QString t1 = prev->CreationTimeXML(); @@ -234,12 +209,12 @@ void TrackFilter::trackfilter_fill_track_list_cb(const route_head* track) /* ca } prev = wpt; } - track_ct++; + + track_list.append(const_cast(track)); } void TrackFilter::trackfilter_minpoint_list_cb(const route_head* track) { - int minimum_points = atoi(opt_minpoints); if (track->rte_waypt_ct < minimum_points) { track_del_head(const_cast(track)); return; @@ -314,8 +289,7 @@ void TrackFilter::trackfilter_title() if (strlen(opt_title) == 0) { fatal(MYNAME "-title: Missing your title!\n"); } - for (int i = 0; i < track_ct; i++) { - route_head* track = track_list[i].track; + for (auto track : qAsConst(track_list)) { trackfilter_pack_init_rte_name(track, QDateTime::fromMSecsSinceEpoch(0, Qt::UTC)); } } @@ -326,34 +300,35 @@ void TrackFilter::trackfilter_title() void TrackFilter::trackfilter_pack() { - int i, j; - - for (i = 1, j = 0; i < track_ct; i++, j++) { - trkflt_t prev = track_list[j]; - if (prev.last_time >= track_list[i].first_time) { - fatal(MYNAME "-pack: Tracks overlap in time! %s >= %s at %d\n", - qPrintable(prev.last_time.toString()), - qPrintable(track_list[i].first_time.toString()), i); + if (!track_list.isEmpty()) { + int i, j; + + for (i = 1, j = 0; i < track_list.size(); i++, j++) { + auto prev_last_time = trackfilter_get_last_time(track_list.at(j)); + auto curr_first_time = trackfilter_get_first_time(track_list.at(i)); + if (prev_last_time >= curr_first_time) { + fatal(MYNAME "-pack: Tracks overlap in time! %s >= %s at %d\n", + qPrintable(prev_last_time.toString()), + qPrintable(curr_first_time.toString()), i); + } } - } - /* we fill up the first track by all other track points */ + /* we fill up the first track by all other track points */ - route_head* master = track_list[0].track; + route_head* master = track_list.first(); - for (i = 1; i < track_ct; i++) { - queue* elem, *tmp; - route_head* curr = track_list[i].track; + while (track_list.size() > 1) { + route_head* curr = track_list.takeAt(1); - QUEUE_FOR_EACH(&curr->waypoint_list, elem, tmp) { - auto wpt = reinterpret_cast(elem); - track_del_wpt(curr, wpt); - track_add_wpt(master, wpt); + queue* elem, *tmp; + QUEUE_FOR_EACH(&curr->waypoint_list, elem, tmp) { + auto wpt = reinterpret_cast(elem); + track_del_wpt(curr, wpt); + track_add_wpt(master, wpt); + } + track_del_head(curr); } - track_del_head(curr); - track_list[i].track = nullptr; } - track_ct = 1; } /******************************************************************************* @@ -362,64 +337,63 @@ void TrackFilter::trackfilter_pack() void TrackFilter::trackfilter_merge() { - int i; + if (!track_list.isEmpty()) { + route_head* master = track_list.first(); - queue* elem, *tmp; - Waypoint* wpt; - route_head* master = track_list[0].track; - - if (track_pts-timeless_pts < 1) { - return; - } + int original_waypt_count = track_waypt_count(); - Waypoint** buff = (Waypoint**)xcalloc(track_pts-timeless_pts, sizeof(*buff)); + QList buff; - int j = 0; - for (i = 0; i < track_ct; i++) { /* put all points into temp buffer */ - route_head* track = track_list[i].track; - QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { - wpt = reinterpret_cast(elem); - if (wpt->creation_time.isValid()) { - buff[j] = new Waypoint(*wpt); - // augment sort key so a stable sort is possible. - buff[j]->extra_data = gb_int2ptr(j); - j++; - // we will put the merged points in one track segment, - // as it isn't clear how track segments in the original tracks - // should relate to the merged track. - // track_add_wpt will set new_trkseg for the first point - // after the sort. - wpt->wpt_flags.new_trkseg = 0; + auto it = track_list.begin(); + while (it != track_list.end()) { /* put all points into temp buffer */ + route_head* track = *it; + queue* elem, *tmp; + QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { + auto wpt = reinterpret_cast(elem); + if (wpt->creation_time.isValid()) { + buff.append(new Waypoint(*wpt)); + // we will put the merged points in one track segment, + // as it isn't clear how track segments in the original tracks + // should relate to the merged track. + // track_add_wpt will set new_trkseg for the first point + // after the sort. + wpt->wpt_flags.new_trkseg = 0; + } + track_del_wpt(track, wpt); // copies any new_trkseg flag forward. + delete wpt; + } + if (it != track_list.begin()) { + track_del_head(track); + it = track_list.erase(it); + } else { + ++it; } - track_del_wpt(track, wpt); // copies any new_trkseg flag forward. - delete wpt; - } - if (track != master) { /* i > 0 */ - track_del_head(track); } - } - track_ct = 1; - qsort(buff, track_pts-timeless_pts, sizeof(*buff), trackfilter_merge_qsort_cb); + std::stable_sort(buff.begin(), buff.end(), trackfilter_merge_sort_cb); - int dropped = timeless_pts; - Waypoint* prev = nullptr; + Waypoint* prev = nullptr; - for (i = 0; i < track_pts-timeless_pts; i++) { - buff[i]->extra_data = nullptr; - wpt = buff[i]; - if ((prev == nullptr) || (prev->GetCreationTime() != wpt->GetCreationTime())) { - track_add_wpt(master, wpt); - prev = wpt; - } else { - delete wpt; - dropped++; + for (auto wpt : buff) { + if ((prev == nullptr) || (prev->GetCreationTime() != wpt->GetCreationTime())) { + track_add_wpt(master, wpt); + prev = wpt; + } else { + delete wpt; + } } - } - xfree(buff); - if (global_opts.verbose_status > 0) { - printf(MYNAME "-merge: %d track point(s) merged, %d dropped.\n", track_pts - dropped, dropped); + if (master->rte_waypt_ct == 0) { + track_del_head(master); + track_list.clear(); + } + + if (global_opts.verbose_status > 0) { + printf(MYNAME "-merge: %d track point(s) merged, %d dropped.\n", track_waypt_count(), original_waypt_count - track_waypt_count()); + } + if ((original_waypt_count > 0) && (track_waypt_count() == 0)) { + warning(MYNAME "-merge: All %d track points have been dropped!\n", original_waypt_count); + } } } @@ -429,161 +403,160 @@ void TrackFilter::trackfilter_merge() void TrackFilter::trackfilter_split() { - route_head* master = track_list[0].track; - int count = master->rte_waypt_ct; + if (track_list.size() > 1) { + fatal(MYNAME "-split: Cannot split more than one track, please pack (or merge) before!\n"); + } else if (!track_list.isEmpty()) { + route_head* master = track_list.first(); + int count = master->rte_waypt_ct; - Waypoint* wpt; - queue* elem, *tmp; - int i, j; - double interval = -1; /* seconds */ - double distance = -1; /* meters */ - - if (count <= 1) { - return; - } + queue* elem, *tmp; + int i, j; + double interval = -1; /* seconds */ + double distance = -1; /* meters */ - /* check additional options */ + if (count <= 1) { + return; + } - opt_interval = (opt_split && (strlen(opt_split) > 0) && (0 != strcmp(opt_split, TRACKFILTER_SPLIT_OPTION))); - if (opt_interval != 0) { - QRegularExpression re("^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+))([dhms])$", QRegularExpression::CaseInsensitiveOption); - assert(re.isValid()); - QRegularExpressionMatch match = re.match(opt_split); - if (match.hasMatch()) { - bool ok; - interval = match.captured(1).toDouble(&ok); - if (!ok || interval <= 0.0) { - fatal(MYNAME ": invalid time interval specified \"%s\", must be a positive number.\n", qPrintable(match.captured(1))); - } + /* check additional options */ + + opt_interval = (opt_split && (strlen(opt_split) > 0) && (0 != strcmp(opt_split, TRACKFILTER_SPLIT_OPTION))); + if (opt_interval != 0) { + QRegularExpression re(R"(^([+-]?(?:\d+(?:\.\d*)?|\.\d+))([dhms])$)", QRegularExpression::CaseInsensitiveOption); + assert(re.isValid()); + QRegularExpressionMatch match = re.match(opt_split); + if (match.hasMatch()) { + bool ok; + interval = match.captured(1).toDouble(&ok); + if (!ok || interval <= 0.0) { + fatal(MYNAME ": invalid time interval specified \"%s\", must be a positive number.\n", qPrintable(match.captured(1))); + } - switch (match.captured(2).at(0).toLower().toLatin1()) { - case 'd': - interval *= SECONDS_PER_DAY; - break; - case 'h': - interval *= SECONDS_PER_HOUR; - break; - case 'm': - interval *= 60; - break; - case 's': - break; - default: - fatal(MYNAME ": invalid time interval unit specified.\n"); - } + switch (match.captured(2).at(0).toLower().toLatin1()) { + case 'd': + interval *= SECONDS_PER_DAY; + break; + case 'h': + interval *= SECONDS_PER_HOUR; + break; + case 'm': + interval *= 60; + break; + case 's': + break; + default: + fatal(MYNAME ": invalid time interval unit specified.\n"); + } #ifdef TRACKF_DBG - printf(MYNAME ": interval %f seconds\n", interval); + printf(MYNAME ": interval %f seconds\n", interval); #endif - } else { - fatal(MYNAME ": invalid timer interval specified \"%s\", must be a positive number, followed by 'd' for days, 'h' for hours, 'm' for minutes or 's' for seconds.\n", opt_split); + } else { + fatal(MYNAME ": invalid timer interval specified \"%s\", must be a positive number, followed by 'd' for days, 'h' for hours, 'm' for minutes or 's' for seconds.\n", opt_split); + } } - } - opt_distance = (opt_sdistance && (strlen(opt_sdistance) > 0) && (0 != strcmp(opt_sdistance, TRACKFILTER_SDIST_OPTION))); - if (opt_distance != 0) { - QRegularExpression re("^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+))([km])$", QRegularExpression::CaseInsensitiveOption); - assert(re.isValid()); - QRegularExpressionMatch match = re.match(opt_sdistance); - if (match.hasMatch()) { - bool ok; - distance = match.captured(1).toDouble(&ok); - if (!ok || distance <= 0.0) { - fatal(MYNAME ": invalid time distance specified \"%s\", must be a positive number.\n", qPrintable(match.captured(1))); - } + opt_distance = (opt_sdistance && (strlen(opt_sdistance) > 0) && (0 != strcmp(opt_sdistance, TRACKFILTER_SDIST_OPTION))); + if (opt_distance != 0) { + QRegularExpression re(R"(^([+-]?(?:\d+(?:\.\d*)?|\.\d+))([km])$)", QRegularExpression::CaseInsensitiveOption); + assert(re.isValid()); + QRegularExpressionMatch match = re.match(opt_sdistance); + if (match.hasMatch()) { + bool ok; + distance = match.captured(1).toDouble(&ok); + if (!ok || distance <= 0.0) { + fatal(MYNAME ": invalid time distance specified \"%s\", must be a positive number.\n", qPrintable(match.captured(1))); + } - switch (match.captured(2).at(0).toLower().toLatin1()) { - case 'k': /* kilometers */ - distance *= 1000.0; - break; - case 'm': /* miles */ - distance *= 1609.344; - break; - default: - fatal(MYNAME ": invalid distance unit specified.\n"); - } + switch (match.captured(2).at(0).toLower().toLatin1()) { + case 'k': /* kilometers */ + distance *= 1000.0; + break; + case 'm': /* miles */ + distance *= 1609.344; + break; + default: + fatal(MYNAME ": invalid distance unit specified.\n"); + } #ifdef TRACKF_DBG - printf(MYNAME ": distance %f meters\n", distance); + printf(MYNAME ": distance %f meters\n", distance); #endif - } else { - fatal(MYNAME ": invalid distance specified \"%s\", must be a positive number followed by 'k' for kilometers or 'm' for miles.\n", opt_sdistance); + } else { + fatal(MYNAME ": invalid distance specified \"%s\", must be a positive number followed by 'k' for kilometers or 'm' for miles.\n", opt_sdistance); + } } - } - trackfilter_split_init_rte_name(master, track_list[0].first_time); + QList buff; - Waypoint** buff = (Waypoint**) xcalloc(count, sizeof(*buff)); + QUEUE_FOR_EACH(&master->waypoint_list, elem, tmp) { + buff.append(reinterpret_cast(elem)); + } - i = 0; - QUEUE_FOR_EACH(&master->waypoint_list, elem, tmp) { - wpt = reinterpret_cast(elem); - buff[i++] = wpt; - } + trackfilter_split_init_rte_name(master, buff.at(0)->GetCreationTime()); - route_head* curr = nullptr; /* will be set by first new track */ + route_head* curr = nullptr; /* will be set by first new track */ - for (i=0, j=1; jGetCreationTime().toLocalTime().date() != - buff[j]->GetCreationTime().toLocalTime().date(); + new_track_flag = buff.at(i)->GetCreationTime().toLocalTime().date() != + buff.at(j)->GetCreationTime().toLocalTime().date(); #ifdef TRACKF_DBG - if (new_track_flag) { - printf(MYNAME ": new day %s\n", qPrintable(buff[j]->GetCreationTime().toLocalTime().date().toString(Qt::ISODate))); - } -#endif - } else { - new_track_flag = true; - - if (distance > 0) { - double rt1 = RAD(buff[i]->latitude); - double rn1 = RAD(buff[i]->longitude); - double rt2 = RAD(buff[j]->latitude); - double rn2 = RAD(buff[j]->longitude); - double curdist = gcdist(rt1, rn1, rt2, rn2); - curdist = radtometers(curdist); - if (curdist <= distance) { - new_track_flag = false; + if (new_track_flag) { + printf(MYNAME ": new day %s\n", qPrintable(buff.at(j)->GetCreationTime().toLocalTime().date().toString(Qt::ISODate))); } +#endif + } else { + new_track_flag = true; + + if (distance > 0) { + double rt1 = RAD(buff.at(i)->latitude); + double rn1 = RAD(buff.at(i)->longitude); + double rt2 = RAD(buff.at(j)->latitude); + double rn2 = RAD(buff.at(j)->longitude); + double curdist = gcdist(rt1, rn1, rt2, rn2); + curdist = radtometers(curdist); + if (curdist <= distance) { + new_track_flag = false; + } #ifdef TRACKF_DBG - else { - printf(MYNAME ": sdistance, %g > %g\n", curdist, distance); - } + else { + printf(MYNAME ": sdistance, %g > %g\n", curdist, distance); + } #endif - } - - if (interval > 0) { - double tr_interval = 0.001 * buff[i]->GetCreationTime().msecsTo(buff[j]->GetCreationTime()); - if (tr_interval <= interval) { - new_track_flag = false; } + + if (interval > 0) { + double tr_interval = 0.001 * buff.at(i)->GetCreationTime().msecsTo(buff.at(j)->GetCreationTime()); + if (tr_interval <= interval) { + new_track_flag = false; + } #ifdef TRACKF_DBG - else { - printf(MYNAME ": split, %g > %g\n", tr_interval, interval); - } + else { + printf(MYNAME ": split, %g > %g\n", tr_interval, interval); + } #endif - } + } - } - if (new_track_flag) { + } + if (new_track_flag) { #ifdef TRACKF_DBG - printf(MYNAME ": splitting new track\n"); + printf(MYNAME ": splitting new track\n"); #endif - curr = route_head_alloc(); - trackfilter_split_init_rte_name(curr, buff[j]->GetCreationTime()); - track_add_head(curr); - } - if (curr != nullptr) { - wpt = buff[j]; - track_del_wpt(master, wpt); - track_add_wpt(curr, wpt); - buff[j] = wpt; + curr = route_head_alloc(); + trackfilter_split_init_rte_name(curr, buff.at(j)->GetCreationTime()); + track_add_head(curr); + track_list.append(curr); + } + if (curr != nullptr) { + track_del_wpt(master, buff.at(j)); + track_add_wpt(curr, buff.at(j)); + } } } - xfree(buff); } /******************************************************************************* @@ -599,15 +572,11 @@ void TrackFilter::trackfilter_move() return; } - for (int i = 0; i < track_ct; i++) { - route_head* track = track_list[i].track; + for (auto track : qAsConst(track_list)) { QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { auto wpt = reinterpret_cast(elem); wpt->creation_time = wpt->creation_time.addSecs(delta); } - - track_list[i].first_time = track_list[i].first_time.addSecs(delta); - track_list[i].last_time = track_list[i].last_time.addSecs(delta); } } @@ -628,8 +597,7 @@ void TrackFilter::trackfilter_synth() fix_type fix = trackfilter_parse_fix(&nsats); - for (int i = 0; i < track_ct; i++) { - route_head* track = track_list[i].track; + for (auto track : qAsConst(track_list)) { bool first = true; QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { auto wpt = reinterpret_cast(elem); @@ -722,7 +690,7 @@ QDateTime TrackFilter::trackfilter_range_check(const char* timestr) return result; } -int TrackFilter::trackfilter_range() /* returns number of track points left after filtering */ +void TrackFilter::trackfilter_range() { QDateTime start, stop; // constructed such that isValid() is false, unlike gpsbabel::DateTime! queue* elem, *tmp; @@ -735,10 +703,11 @@ int TrackFilter::trackfilter_range() /* returns number of track points left aft stop = trackfilter_range_check(opt_stop); } - int dropped = 0; + int original_waypt_count = track_waypt_count(); - for (int i = 0; i < track_ct; i++) { - route_head* track = track_list[i].track; + auto it = track_list.begin(); + while (it != track_list.end()) { + route_head* track = *it; QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { auto wpt = reinterpret_cast(elem); @@ -756,21 +725,20 @@ int TrackFilter::trackfilter_range() /* returns number of track points left aft if (!inside) { track_del_wpt(track, wpt); delete wpt; - dropped++; } } if (track->rte_waypt_ct == 0) { track_del_head(track); - track_list[i].track = nullptr; + it = track_list.erase(it); + } else { + ++it; } } - if ((track_pts > 0) && (dropped == track_pts)) { - warning(MYNAME "-range: All %d track points have been dropped!\n", track_pts); + if ((original_waypt_count > 0) && (track_waypt_count() == 0)) { + warning(MYNAME "-range: All %d track points have been dropped!\n", original_waypt_count); } - - return track_pts - dropped; } /******************************************************************************* @@ -779,45 +747,50 @@ int TrackFilter::trackfilter_range() /* returns number of track points left aft void TrackFilter::trackfilter_seg2trk() { - for (int i = 0; i < track_ct; i++) { - queue* elem, *tmp; - route_head* src = track_list[i].track; - route_head* dest = nullptr; - route_head* insert_point = src; - int trk_seg_num = 1; - bool first = true; + if (!track_list.isEmpty()) { + QList new_track_list; + for (auto src : qAsConst(track_list)) { + queue* elem, *tmp; + new_track_list.append(src); + route_head* dest = nullptr; + route_head* insert_point = src; + int trk_seg_num = 1; + bool first = true; + + QUEUE_FOR_EACH(&src->waypoint_list, elem, tmp) { + auto wpt = reinterpret_cast(elem); + if (wpt->wpt_flags.new_trkseg && !first) { - QUEUE_FOR_EACH(&src->waypoint_list, elem, tmp) { - auto wpt = reinterpret_cast(elem); - if (wpt->wpt_flags.new_trkseg && !first) { + dest = route_head_alloc(); + dest->rte_num = src->rte_num; + /* name in the form TRACKNAME #n */ + if (!src->rte_name.isEmpty()) { + dest->rte_name = QString("%1 #%2").arg(src->rte_name).arg(++trk_seg_num); + } - dest = route_head_alloc(); - dest->rte_num = src->rte_num; - /* name in the form TRACKNAME #n */ - if (!src->rte_name.isEmpty()) { - dest->rte_name = QString("%1 #%2").arg(src->rte_name).arg(++trk_seg_num); + /* Insert after original track or after last newly + * created track */ + track_insert_head(dest, insert_point); + insert_point = dest; + new_track_list.append(dest); } - /* Insert after original track or after last newly - * created track */ - track_insert_head(dest, insert_point); - insert_point = dest; - } - - /* If we found a track separator, transfer from original to - * new track. We have to reset new_trkseg temporarily to - * prevent track_del_wpt() from copying it to the next track - * point. - */ - if (dest) { - unsigned orig_new_trkseg = wpt->wpt_flags.new_trkseg; - wpt->wpt_flags.new_trkseg = 0; - track_del_wpt(src, wpt); - wpt->wpt_flags.new_trkseg = orig_new_trkseg; - track_add_wpt(dest, wpt); + /* If we found a track separator, transfer from original to + * new track. We have to reset new_trkseg temporarily to + * prevent track_del_wpt() from copying it to the next track + * point. + */ + if (dest) { + unsigned orig_new_trkseg = wpt->wpt_flags.new_trkseg; + wpt->wpt_flags.new_trkseg = 0; + track_del_wpt(src, wpt); + wpt->wpt_flags.new_trkseg = orig_new_trkseg; + track_add_wpt(dest, wpt); + } + first = false; } - first = false; } + track_list = new_track_list; } } @@ -827,30 +800,30 @@ void TrackFilter::trackfilter_seg2trk() void TrackFilter::trackfilter_trk2seg() { - route_head* master = track_list[0].track; + if (!track_list.isEmpty()) { + route_head* master = track_list.first(); - for (int i = 1; i < track_ct; i++) { - queue* elem, *tmp; - route_head* curr = track_list[i].track; + while (track_list.size() > 1) { + route_head* curr = track_list.takeAt(1); - bool first = true; - QUEUE_FOR_EACH(&curr->waypoint_list, elem, tmp) { - auto wpt = reinterpret_cast(elem); + queue* elem, *tmp; + bool first = true; + QUEUE_FOR_EACH(&curr->waypoint_list, elem, tmp) { + auto wpt = reinterpret_cast(elem); - unsigned orig_new_trkseg = wpt->wpt_flags.new_trkseg; - wpt->wpt_flags.new_trkseg = 0; - track_del_wpt(curr, wpt); - wpt->wpt_flags.new_trkseg = orig_new_trkseg; - track_add_wpt(master, wpt); - if (first) { - wpt->wpt_flags.new_trkseg = 1; - first = false; + unsigned orig_new_trkseg = wpt->wpt_flags.new_trkseg; + wpt->wpt_flags.new_trkseg = 0; + track_del_wpt(curr, wpt); + wpt->wpt_flags.new_trkseg = orig_new_trkseg; + track_add_wpt(master, wpt); + if (first) { + wpt->wpt_flags.new_trkseg = 1; + first = false; + } } + track_del_head(curr); } - track_del_head(curr); - track_list[i].track = nullptr; } - track_ct = 1; } /******************************************************************************* @@ -861,7 +834,7 @@ TrackFilter::faketime_t TrackFilter::trackfilter_faketime_check(const char* time { faketime_t result; - QRegularExpression re("^(f?)(\\d{0,14})(?:\\+(\\d{1,10}))?$"); + QRegularExpression re(R"(^(f?)(\d{0,14})(?:\+(\d{1,10}))?$)"); assert(re.isValid()); QRegularExpressionMatch match = re.match(timestr); if (match.hasMatch()) { @@ -903,9 +876,7 @@ void TrackFilter::trackfilter_faketime() assert(opt_faketime != nullptr); faketime_t faketime = trackfilter_faketime_check(opt_faketime); - for (int i = 0; i < track_ct; i++) { - route_head* track = track_list[i].track; - + for (auto track : qAsConst(track_list)) { QUEUE_FOR_EACH(&track->waypoint_list, elem, tmp) { auto wpt = reinterpret_cast(elem); @@ -993,8 +964,6 @@ void TrackFilter::init() RteHdFunctor trackfilter_segment_head_f(this, &TrackFilter::trackfilter_segment_head); RteHdFunctor trackfilter_fill_track_list_cb_f(this, &TrackFilter::trackfilter_fill_track_list_cb); - int count = track_count(); - /* * check time presence only if required. Options that NOT require time: * @@ -1012,34 +981,25 @@ void TrackFilter::init() need_time = true; } - track_ct = 0; - track_pts = 0; - // Perform segmenting first. if (opt_segment) { track_disp_all(trackfilter_segment_head_f, nullptr, nullptr); } - if (count > 0) { - track_list = new trkflt_t[count]; - + track_list.clear(); + if (track_count() > 0) { /* check all tracks for time and order (except merging) */ track_disp_all(trackfilter_fill_track_list_cb_f, nullptr, nullptr); if (need_time) { - qsort(track_list, track_ct, sizeof(*track_list), trackfilter_init_qsort_cb); + std::sort(track_list.begin(), track_list.end(), trackfilter_init_sort_cb); } - } else { - track_list = nullptr; } } void TrackFilter::deinit() { - delete[] track_list; - track_list = nullptr; - track_ct = 0; - track_pts = 0; + track_list.clear(); } /******************************************************************************* @@ -1050,7 +1010,7 @@ void TrackFilter::process() { RteHdFunctor trackfilter_minpoint_list_cb_f(this, &TrackFilter::trackfilter_minpoint_list_cb); - if (track_ct == 0) { + if (track_list.isEmpty()) { return; /* no track(s), no fun */ } @@ -1092,6 +1052,7 @@ void TrackFilter::process() opts--; trackfilter_faketime(); + // tracks and points within tracks may now be out of order. if (opts == 0) { return; @@ -1100,7 +1061,7 @@ void TrackFilter::process() deinit(); /* reinitialize */ init(); - if (track_ct == 0) { + if (track_list.isEmpty()) { return; /* no more track(s), no more fun */ } } @@ -1114,26 +1075,29 @@ void TrackFilter::process() } trackfilter_range(); + // track_list may? now be invalid! if (opts == 0) { return; } + // TODO: Is this needed if range maintains the track_list? deinit(); /* reinitialize */ init(); - if (track_ct == 0) { + if (track_list.isEmpty()) { return; /* no more track(s), no more fun */ } - } if (opt_seg2trk != nullptr) { trackfilter_seg2trk(); + // track_list may? now be invalid! if (--opts == 0) { return; } + // TODO: Is this needed if seg2trk maintains the track_list? deinit(); /* reinitialize */ init(); } @@ -1170,15 +1134,17 @@ void TrackFilter::process() } if ((opt_split != nullptr) || (opt_sdistance != nullptr)) { - if (track_ct > 1) { - fatal(MYNAME "-split: Cannot split more than one track, please pack (or merge) before!\n"); - } - trackfilter_split(); + // track_list may? now be invalid! } // Performed last as previous options may have created "small" tracks. - if ((opt_minpoints != nullptr) && atoi(opt_minpoints) > 0) { + if (opt_minpoints != nullptr) { + bool ok; + minimum_points = QString(opt_minpoints).toInt(&ok); + if (!ok || minimum_points <= 0) { + fatal(MYNAME "-minimum_points: option value must be a positive integer!\n"); + } track_disp_all(trackfilter_minpoint_list_cb_f, nullptr, nullptr); } } diff --git a/trackfilter.h b/trackfilter.h index 8eae7fb87..96dd8cecc 100644 --- a/trackfilter.h +++ b/trackfilter.h @@ -78,6 +78,7 @@ private: char* opt_faketime = nullptr; char* opt_discard = nullptr; char* opt_minpoints = nullptr; + int minimum_points{0}; arglist_t args[19] = { { @@ -169,25 +170,18 @@ private: ARG_TERMINATOR }; - struct trkflt_t { - route_head* track{nullptr}; - QDateTime first_time; - QDateTime last_time; - }; - - trkflt_t* track_list = nullptr; - int track_ct = 0; - int track_pts = 0; - int timeless_pts = 0; + QList track_list; int opt_interval = 0; int opt_distance = 0; bool need_time; /* initialized within trackfilter_init */ int trackfilter_opt_count(); qint64 trackfilter_parse_time_opt(const char* arg); - static int trackfilter_init_qsort_cb(const void* a, const void* b); - static int trackfilter_merge_qsort_cb(const void* a, const void* b); + static bool trackfilter_init_sort_cb(const route_head* ha, const route_head* hb); + static bool trackfilter_merge_sort_cb(const Waypoint* wa, const Waypoint* wb); fix_type trackfilter_parse_fix(int* nsats); + static QDateTime trackfilter_get_first_time(const route_head* track); + static QDateTime trackfilter_get_last_time(const route_head* track); void trackfilter_fill_track_list_cb(const route_head* track); /* callback for track_disp_all */ void trackfilter_minpoint_list_cb(const route_head* track); @@ -207,7 +201,7 @@ private: void trackfilter_synth(); QDateTime trackfilter_range_check(const char* timestr); - int trackfilter_range(); /* returns number of track points left after filtering */ + void trackfilter_range(); void trackfilter_seg2trk();